// renderer.hpp
//

#ifndef _RENDERER_HPP
#define _RENDERER_HPP

#include "base.hpp"
#include "scene.hpp"

class Scene;


typedef size_t ProgramID;
typedef size_t PipelineID;
typedef size_t RenderModeID;


// UniformID
//

// Program
//
struct Program
{
  ProgramID id;
  std::string name;
  std::string vertex_shader;
  std::string fragment_shader;

  // context
  bool loaded{false};
  wgl::Program wgl_program{};
  wgl::UniformSlot m4_projection;
  wgl::UniformSlot m4_model;
};


// Pipeline
//
struct Pipeline
{
  PipelineID id;
  std::string name;
  ProgramID program;
};


// PipelineBinding
//
struct PipelineBinding
{
  EntityFamilyID entity_family;
  PipelineID pipeline;
};


// RenderMode
//
struct RenderMode
{
  RenderModeID id;
  std::string name;
  // pipelines by entity type
  std::vector<PipelineID> pipelines;
};


// Renderer
//
class Renderer
{
public:
  ProgramID register_program ( std::string name,
                               std::string vertex_shader,
                               std::string fragment_shader );
  PipelineID register_pipeline  ( std::string name,
                                  ProgramID program );
  RenderModeID register_render_mode ( std::string name,
                                      const std::vector<PipelineBinding> &pipeline_bindings );

  PipelineID get_pipeline_id ( const std::string &name );

  void setup_pipeline ( PipelineID pipeline_id );
  void use_program ( ProgramID program_id );
  
  void render ( Scene &scene );

private:
  std::vector<Program> registered_programs;
  std::vector<Pipeline> registered_pipelines;
  std::vector<RenderMode> registered_render_modes;

  // context
  RenderModeID render_mode_id{0};
  // [FIXME] use 0 as nul pipeline
  PipelineID current_pipeline{std::numeric_limits<PipelineID>::max()};
  ProgramID current_program{std::numeric_limits<ProgramID>::max()};

  wgl::Camera camera{};
};

#endif
